package org.shagin.jfin.ui.editor.budget;

import java.awt.BorderLayout;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;

import org.shagin.jfin.core.Debug;
import org.shagin.jfin.data.model.IBudget;
import org.shagin.jfin.ui.budget.item.BudgetItemViewPane;
import org.shagin.jfin.ui.budget.item.impl.AbstractBudgetItemView;
import org.shagin.jfin.ui.budget.tree.BudgetTree;
import org.shagin.ui.TreeModelListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class BudgetEditorPane.
 */
@SuppressWarnings("serial")
public class BudgetEditorPane extends JPanel {

    private static final Logger log = LoggerFactory
            .getLogger(BudgetEditorPane.class);

    private IBudget budget;
    private BudgetTree tree;
    private BudgetItemViewPane itemViewPane = new BudgetItemViewPane();
    private JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
    private BudgetTreeModelListener budgetTreeListener = new BudgetTreeModelListener();
    private BudgetTreeSelectionListener budgetTreeSelectionListener = new BudgetTreeSelectionListener();

    /**
     * The listener interface for receiving budgetTreeModel events. The class
     * that is interested in processing a budgetTreeModel event implements this
     * interface, and the object created with that class is registered with a
     * component using the component's
     * <code>addBudgetTreeModelListener<code> method. When
     * the budgetTreeModel event occurs, that object's appropriate
     * method is invoked.
     * 
     * @see BudgetTreeModelEvent
     */
    private class BudgetTreeModelListener extends TreeModelListenerAdapter {
    }

    /**
     * The listener interface for receiving budgetTreeSelection events. The
     * class that is interested in processing a budgetTreeSelection event
     * implements this interface, and the object created with that class is
     * registered with a component using the component's
     * <code>addBudgetTreeSelectionListener<code> method. When
     * the budgetTreeSelection event occurs, that object's appropriate
     * method is invoked.
     * 
     * @see BudgetTreeSelectionEvent
     */
    private class BudgetTreeSelectionListener implements TreeSelectionListener {

        /**
         * Gets the user object.
         * 
         * @param e the e
         * @return the user object
         */
        private Object getUserObject(TreeSelectionEvent e) {
            DefaultMutableTreeNode treeNode = getMutableTreeNode(e);
            Object result = treeNode.getUserObject();
            if (result instanceof String)
                result = treeNode;
            return result;
        }

        /**
         * Gets the mutable tree node.
         * 
         * @param e the e
         * @return the mutable tree node
         */
        private DefaultMutableTreeNode getMutableTreeNode(TreeSelectionEvent e) {
            return ((DefaultMutableTreeNode) e.getPath().getLastPathComponent());
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void valueChanged(TreeSelectionEvent e) {
            Debug.traceEnter(log);
            Object obj = getUserObject(e);
            log.debug("Selected object : " + obj.getClass().getSimpleName());
            showView(obj);
        }
    }

    /**
     * Instantiates a new budget editor pane.
     * 
     * @param budget the budget
     */
    public BudgetEditorPane(IBudget budget) {
        Debug.traceEnter(log);
        setLayout(new BorderLayout());
        tree = new BudgetTree(budget);
        tree.addTreeModelListener(budgetTreeListener);
        tree.addTreeSelectionListener(budgetTreeSelectionListener);
        JScrollPane treeView = new JScrollPane(tree);        
        splitPane.setLeftComponent(treeView);
        splitPane.setRightComponent(itemViewPane);        
        add(splitPane, BorderLayout.CENTER);        
        setBudget(budget);        
    }

    /**
     * Show view.
     * 
     * @param obj the obj
     */
    public void showView(Object obj) {
        Debug.traceEnter(log, obj);
        AbstractBudgetItemView budgetItemView = getBudgetItemView(obj);
        budgetItemView.setBudgetItem(obj);
        itemViewPane.setView(budgetItemView);
    }

    /**
     * Gets the budget.
     * 
     * @return the budget
     */
    public IBudget getBudget() {
        return budget;
    }

    /**
     * Sets the budget.
     * 
     * @param budget the new budget
     */
    public void setBudget(IBudget budget) {
        Debug.traceEnter(log);
        this.budget = budget;
        tree.setBudget(budget);
    }

    /**
     * Gets the budget item view.
     * 
     * @param object the object
     * @return the budget item view
     */
    private AbstractBudgetItemView getBudgetItemView(Object object) {
        Debug.traceEnter(log);
        AbstractBudgetItemView result = itemViewPane.findOrCrete(object);
        return result;
    }
}
